#include "PCResource_gui.h"
#include "lvgl/lvgl.h"
#include "themes/PCResource_theme_default.h"
#include "themes/PCResource_theme_light.h"
#include "themes/PCResource_theme_sky.h"
#include "themes/PCResource_theme_miku.h"
#include "themes/PCResource_theme_bilibili.h"

#define MAX_THEME 10 // 最大支持主题数

// UI回调函数集合
static gui_opt_t gui_opts;

// 界面容器
static lv_obj_t *cont;

// 主题操作函数集合
static gui_theme_operations theme_opts[MAX_THEME];

// 当前主题索引
static int active_theme = 0;

// 已添加的主题数目
static int total_theme = 0;

/**
 *@brief 初始化基本UI
 *@param opts 回调函数集合
 */
void pc_resource_gui_init(gui_opt_t *opts)
{
  cont = lv_obj_create(lv_scr_act());
  lv_obj_set_size(cont, 1024, 600);
  lv_obj_clear_flag(cont, LV_OBJ_FLAG_SCROLLABLE);           // 禁止对象滚动
  lv_obj_set_style_border_width(cont, 0, LV_STATE_DEFAULT);  // 边框宽度0
  lv_obj_set_style_pad_all(cont, 0, LV_STATE_DEFAULT);       // 四周填充宽度0
  lv_obj_set_style_outline_width(cont, 0, LV_STATE_DEFAULT); // 外部线条宽度0
  lv_obj_center(cont);

  if (opts != NULL) // 设置回调函数集合
    memcpy(&gui_opts, opts, sizeof(gui_opt_t));

  gui_opts.set_next_theme = pc_resource_gui_set_next_theme;

  // 添加主题
  pc_resource_gui_add_theme_list("default", &default_theme);
  pc_resource_gui_add_theme_list("light", &light_theme);
  pc_resource_gui_add_theme_list("sky", &sky_theme);
  pc_resource_gui_add_theme_list("miku", &miku_theme);
  pc_resource_gui_add_theme_list("bilibili", &bilibili_theme);
  theme_opts[0].init(cont, &gui_opts);
}

/**
 *@brief 添加主题
 *@param name 主题名称
 *@param opts 主题操作函数集
 */
void pc_resource_gui_add_theme_list(const char *name, gui_theme_operations *opts)
{
  if (opts == NULL && total_theme >= MAX_THEME)
    return;

  memcpy(&theme_opts[total_theme], opts, sizeof(gui_theme_operations)); // 设置主题操作函数集

  total_theme++;
}

/**
 *@brief 更新UI显示数据
 *@param info PC硬件资源数据
 */
void pc_resource_gui_update_data(PCResInfo *info)
{
  if (theme_opts[active_theme].update != NULL)
    theme_opts[active_theme].update(info);
}

/**
 *@brief 切换UI主题
 *@param tag 切换的主题索引
 */
void pc_resource_gui_change_theme(int tag)
{
  if (tag < 0 || tag >= total_theme)
    return;

  if (theme_opts[active_theme].release != NULL)
    theme_opts[active_theme].release(); // 释放上一个主题的资源

  if (theme_opts[tag].init != NULL)
    theme_opts[tag].init(cont, &gui_opts); // 初始化新的主题

  active_theme = tag; // 设置新的活跃主题
}

/**
 *@brief 切换到下一个主题
 */
void pc_resource_gui_set_next_theme(void)
{
  int tag = active_theme;

  tag = tag < total_theme - 1 ? tag + 1 : 0;

  pc_resource_gui_change_theme(tag);
}

/**
 *@brief 释放UI资源
 */
void pc_resource_gui_release(void)
{
  if (theme_opts[active_theme].release != NULL)
    theme_opts[active_theme].release();

  lv_obj_del(cont);
}

/**
 *@brief 图表自动刻度设置
 *@param chart 图表
 *@param series 数据系列
 *@param min 刻度最小值设定
 *@param max 刻度最大值的下限
 *@note 此函数仅供主题使用
 */
void chart_auto_scale(lv_obj_t *chart, lv_chart_series_t *series, int min, int max)
{
    int max_value = max;
    
    int total_point = lv_chart_get_point_count(chart);    //获取总点数
    lv_coord_t *array = lv_chart_get_y_array(chart, series);   //获取点数组

    for(int j = 0; j < total_point; j++)
      max_value = max_value < array[j] ? array[j] : max_value;    //计算当前所有点中最大值

    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, min, max_value);
}

/**
 *@brief 图表 数据下方区域填充绘制回调
 *@note 此函数仅供主题使用
 */
void chart_draw_evnet_cb(lv_event_t *e)
{
  lv_obj_t *obj = lv_event_get_target(e);

  /*Add the faded area before the lines are drawn*/
  lv_obj_draw_part_dsc_t *dsc = lv_event_get_draw_part_dsc(e);
  if (dsc->part == LV_PART_ITEMS)
  {
    if (!dsc->p1 || !dsc->p2)
      return;

    /*Add a line mask that keeps the area below the line*/
    lv_draw_mask_line_param_t line_mask_param;
    lv_draw_mask_line_points_init(&line_mask_param, dsc->p1->x, dsc->p1->y, dsc->p2->x, dsc->p2->y, LV_DRAW_MASK_LINE_SIDE_BOTTOM);
    int16_t line_mask_id = lv_draw_mask_add(&line_mask_param, NULL);

    /*Add a fade effect: transparent bottom covering top*/
    lv_coord_t h = lv_obj_get_height(obj);
    lv_draw_mask_fade_param_t fade_mask_param;
    lv_draw_mask_fade_init(&fade_mask_param, &obj->coords, LV_OPA_COVER, obj->coords.y1 + h / 8, LV_OPA_TRANSP, obj->coords.y2);
    int16_t fade_mask_id = lv_draw_mask_add(&fade_mask_param, NULL);

    /*Draw a rectangle that will be affected by the mask*/
    lv_draw_rect_dsc_t draw_rect_dsc;
    lv_draw_rect_dsc_init(&draw_rect_dsc);
    draw_rect_dsc.bg_opa = LV_OPA_80;
    draw_rect_dsc.bg_color = dsc->line_dsc->color;

    lv_area_t a;
    a.x1 = dsc->p1->x;
    a.x2 = dsc->p2->x - 1;
    a.y1 = LV_MIN(dsc->p1->y, dsc->p2->y);
    a.y2 = obj->coords.y2;
    lv_draw_rect(dsc->draw_ctx, &draw_rect_dsc, &a);

    /*Remove the masks*/
    lv_draw_mask_free_param(&line_mask_param);
    lv_draw_mask_free_param(&fade_mask_param);
    lv_draw_mask_remove_id(line_mask_id);
    lv_draw_mask_remove_id(fade_mask_id);
  }
}